﻿using System;
using System.Collections.Generic;
using MugenInjection.Delegates;
using MugenInjection.Infrastructure;
using MugenInjection.Interface;

namespace MugenInjection.Bindings
{
    /// <summary>
    /// Represents the method binding.
    /// </summary>
    public class MethodBinding : BindingBase
    {
        #region Fields

        private readonly IActivator _activator;
        private MethodBindingDelegate _method;

        #endregion

        #region Constructor

        /// <summary>
        /// Initializes a new instance of the <see cref="MethodBinding" /> class.
        /// </summary>
        /// <param name="method">The specified method for activate object.</param>
        /// <param name="activator">The specified <see cref="IActivator"/> for activate object.</param>
        /// <param name="services">The specified services types.</param>
        /// <param name="scopeLifecycle">The specified <see cref="IScopeLifecycle"/></param>
        /// <param name="parameters">The specified parameters.</param>
        /// <param name="canResolve">The specified condition for can resolve method.</param>
        public MethodBinding(MethodBindingDelegate method, IActivator activator, IList<Type> services,
                             IScopeLifecycle scopeLifecycle,
                             IEnumerable<IInjectionParameter> parameters, CanResolveBindingDelegate canResolve)
            : base(services, scopeLifecycle, parameters, canResolve)
        {
            Validate.ArgumentNotNull(method, "method");
            _method = method;
            _activator = activator;

            ActivatedActions.Add(InjectorUtilsInternal.ActivateInitializable);
            ActivatedActions.Add(InjectorUtilsInternal.ActivateStartable);
            if (scopeLifecycle != null && scopeLifecycle.ReleaseObjectActions != null &&
                !scopeLifecycle.ReleaseObjectActions.IsReadOnly)
                scopeLifecycle.ReleaseObjectActions.Add(InjectorUtilsInternal.DeactivateStartable);
        }

        #endregion

        #region Properties

        /// <summary>
        /// Gets <see cref="IActivator"/> for the current binding.
        /// </summary>
        public IActivator Activator
        {
            get { return _activator; }
        }

        #endregion

        #region Overrides of BindingBase

        /// <summary>
        /// Resolves instance for the specified <see cref="IBindingContext"/>.
        /// </summary>
        /// <param name="bindingContext">The specified <see cref="IBindingContext"/>.</param>
        /// <returns>An instance of the service.</returns>
        protected override object ResolveService(IBindingContext bindingContext)
        {
            object obj = _method(bindingContext);
            if (_activator != null)
                _activator.Activate(ref obj, bindingContext);
            return obj;
        }

        /// <summary>
        /// Releases resources held by the object.
        /// </summary>
        protected override void Dispose(bool disposing)
        {
            if (disposing && !IsDisposed)
            {
                if (_activator != null)
                    _activator.Dispose();
                _method = null;
            }
            base.Dispose(disposing);
        }

        #endregion
    }
}